import struct
import json
import ssl
import socket
import CONSTANTS
import traceback
import time
import redis
from mpns import MPNSTile, MPNSToast
from threading import Thread
from database import cache
import os
os.environ['http_proxy'] = ''
import requests

redis_conn = redis.Redis()


class Android:
    @staticmethod
    def push(i_task_queue, i_msg, i_app_id):
        v_workers = []
        for i in range(5):
            v_worker = Thread(target=Android.minipush, args=(i_task_queue, i_msg, i_app_id))
            v_worker.start()
            v_workers.append(v_worker)
        for woker in v_workers:
            woker.join()
        print 'done android'

    @staticmethod
    def minipush(i_task_queue, msg, app_id):
        v_tmp = 0
        try:
            v_tokens = cache().get_and_del(i_task_queue, 900)
            while v_tokens:
                try:
                    # apiKey = CONSTANTS.apikey[app_id]
                    url = 'https://android.googleapis.com/gcm/send'
                    json_data = json.dumps({'registration_ids': v_tokens, 'data': {"message": msg, }})
                    headers = {'Content-Type': 'application/json', 'Authorization': 'key=%s' % CONSTANTS.apikey[app_id]}
                    v_status = CONSTANTS.STATUS.FAILED
                    for _ in range(5):
                        try:
                            v_res = requests.post(url, data=json_data, headers=headers, allow_redirects=True)
                            #print 'android', len(v_tokens)
                            v_status = CONSTANTS.STATUS.SUCCESS
                            break
                        except:
                            traceback.print_exc()                            
                            time.sleep(1)
                            pass
                    #log queue
                    v_tmp = 1
                    for token in v_tokens:
                        redis_conn.zincrby('pushed_log', str((int(i_task_queue.split('_')[0]), token, "", time.mktime(time.localtime()), v_status)), amount=1)
                except:
                    traceback.print_exc()
                    for token in v_tokens:
                        redis_conn.zincrby('pushed_log', str((int(i_task_queue.split('_')[0]), token, "", time.mktime(time.localtime()), CONSTANTS.STATUS.FAILED)), amount=1)
                v_tokens = cache().get_and_del(i_task_queue, 900)
        except:
            traceback.print_exc()
        return v_tmp


class iOS:
    @staticmethod
    def connectedAPNS(app_id):
        print 'connecting to apple'
        v_tmp = None
        while True:
            try:
                s = socket.socket()
                if app_id == CONSTANTS.APP.IONLINE:
                    v_tmp = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, certfile='ionline.pem', keyfile='ionline.key')
                elif app_id == CONSTANTS.APP.ICO:
                    v_tmp = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, certfile='ionline.pem', keyfile='ionline.key')
                elif app_id == CONSTANTS.app_name2id['itest']:
                    v_tmp = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, certfile='ionline.pem', keyfile='ionline.key')
                else:
                    v_tmp = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, certfile='ionline.pem', keyfile='ionline.key')
                v_tmp.connect(('gateway.push.apple.com', 2195))
                print 'connected to apple'
                break
            except:
                traceback.print_exc()
                time.sleep(1)
        return v_tmp

    @staticmethod
    def push(i_task_queue, i_msg, i_app_id):
        v_workers = []
        if len(redis_conn.zrange(i_task_queue, 0, 20)) > 10:
            for i in range(5):
                v_worker = Thread(target=iOS.minipush, args=(i_task_queue, i_msg, i_app_id))
                v_worker.start()
                v_workers.append(v_worker)
            for woker in v_workers:
                woker.join()
        else:
            iOS.minipush(i_task_queue, i_msg, i_app_id)
        print 'done ios'

    @staticmethod
    def minipush(i_task_queue, msg, app_id):
        v_tmp = 1
        try:
            v_payLoad = {
                'aps': {
                    'alert': msg,
                    'sound': 'default',
                    'badge': 0,
                },
            }
            data = json.dumps(v_payLoad)
            v_ssl_socket = iOS.connectedAPNS(app_id)
            token = cache().get_and_del(i_task_queue, 1)
            while token:
                try:
                    token = token[0].replace(' ', '')
                    byteToken = token.decode('hex')  # Python 2
                    v_format = '!BH32sH%ds' % len(data)
                    v_status = CONSTANTS.STATUS.FAILED
                    try:
                        theNotification = struct.pack(v_format, 0, 32, byteToken, len(data), data)
                    except:
                        continue
                    for _ in range(5):
                        try:
                            v_written = 0
                            while v_written < len(theNotification):
                                v_count = v_ssl_socket.write(theNotification[v_written:])
                                v_written = v_written + v_count
                            v_status = CONSTANTS.STATUS.SUCCESS
                            break
                        except Exception:
                            traceback.print_exc()
                            time.sleep(1)
                            try:
                                v_ssl_socket = iOS.connectedAPNS(app_id)
                            except Exception:
                                traceback.print_exc()
                                continue
                    redis_conn.zincrby('pushed_log', str((int(i_task_queue.split('_')[0]), token, "", time.mktime(time.localtime()), v_status)), amount=1)
                except Exception:
                    redis_conn.zincrby('pushed_log', str((int(i_task_queue.split('_')[0]), token, "", time.mktime(time.localtime()), CONSTANTS.STATUS.FAILED)), amount=1)
                    traceback.print_exc()
                token = cache().get_and_del(i_task_queue, 1)
            try:
                v_ssl_socket.close()
            except Exception:
                traceback.print_exc()
        except Exception:
            traceback.print_exc()
            v_tmp = 0
        return v_tmp


class WindowPhone:
    @staticmethod
    def push(self):
        uri = 'http://db3.notify.live.net/throttledthirdparty/01.00/ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
        toast = MPNSToast()
        tile = MPNSTile()
        toast.send(uri, {'text1': 'Hello', 'text2': 'Windows Phone'})
        toast.send(uri, {'text1': 'Tap this message', 'text2': 'To open application'})
        tile.send(uri, {'title': 'Tile title'})